package com.example.hello.views.assignments;

import com.example.hello.*;
import com.example.hello.POJO.*;
import com.example.hello.views.Collection;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.Users;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.Page;
import com.vaadin.ui.*;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import java.io.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class Assignment extends Collection {

    private static UserPOJO currentUser;

    private HorizontalLayout layout = new HorizontalLayout();

    private BootstrapAlert alert = new BootstrapAlert("Log in!");
    private HorizontalLayout form = new HorizontalLayout();
    private VerticalLayout pending = new VerticalLayout();
    private BootstrapButton editAssignment = new BootstrapButton("Edit Assignment");

    private AssignmentPOJO assignment;

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        this.assignment = Assignment.GETAssignment(NAME);
//        if (this.assignment == null) assignment = new AssignmentPOJO();

        if (HelloUI.getCurrent().getSession().getAttribute("isLoggedIn").equals(false)) {
            alert.setVisible(true);
            form.setVisible(false);
            pending.setVisible(false);
        } else {
            alert.setVisible(false);
            form.setVisible(true);
            pending.setVisible(currentUser.getRole(assignment).ordinal() < 2);
        }

        editAssignment.setVisible(currentUser.getRole(assignment).ordinal() >= 2);
    }

    public Assignment(String NAME, AssignmentPOJO assignment) {
        super(NAME);
        this.assignment = assignment;

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        if (this.assignment == null) this.assignment = new AssignmentPOJO();

        initAssignmentBody();
        initAssignmentMarks();

        addComponent(layout);
    }

    public void initAssignmentBody() {
        VerticalLayout body = new VerticalLayout();

        body.setWidth("650px");
        body.addStyleName("layout-margin");

        BootstrapHeading name = new BootstrapHeading(5, assignment.getTrack() + " - " + assignment.getName());
        List<String> description = new LinkedList<>();
        BootstrapButton submitFile = new BootstrapButton("Submit");

        // get assignment description and split into separate paragraphs
        Collections.addAll(description, assignment.getDescription().split("\n"));
        submitFile.setType(BootstrapButton.Type.PRIMARY);

        body.addComponents(name, alert);
        for (String paragraph : description) body.addComponent(new BootstrapParagraph(paragraph));
        body.addComponent(form);

        alert.setText("You need to log in to submit assignments");
        alert.setClose(false);

        final BootstrapLabel submissionName = new BootstrapLabel();
        final BootstrapProgressBar progress = new BootstrapProgressBar();
        progress.setVisible(false);
        final Upload upload = new Upload(null, new Upload.Receiver() {
            @Override
            public OutputStream receiveUpload(String filename, String mimeType) {
                try {
                    File base = new File("/users/daneorie/Desktop/test/");
                    if (base.isDirectory() || base.mkdir())
                        return new FileOutputStream(new File(base + File.separator + filename));
                } catch (FileNotFoundException e) {
                    new Notification("Could not open file",
                            e.getMessage(),
                            Notification.Type.ERROR_MESSAGE).show(Page.getCurrent());
                }
                return null;
            }
        });
        Upload.SucceededListener succeededListener = new Upload.SucceededListener() {
            @Override
            public void uploadSucceeded(Upload.SucceededEvent event) {
                submissionName.setText(event.getFilename());
                form.removeAllComponents();
                form.addComponent(submissionName);
                form.setComponentAlignment(submissionName, Alignment.MIDDLE_CENTER);
            }
        };
        Upload.ProgressListener progressListener = new Upload.ProgressListener() {
            @Override
            public void updateProgress(long readBytes, long contentLength) {
                progress.setPercent((int) (readBytes / contentLength) * 100);
            }
        };

        upload.addSucceededListener(succeededListener);
        upload.addProgressListener(progressListener);
        upload.setButtonCaption(null);
        upload.setTabIndex(1);
        submitFile.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                progress.setVisible(true);
                upload.submitUpload();
            }
        });

        form.addComponents(upload, progress, submitFile);
        form.setWidth("100%");

        layout.addComponent(body);
    }

    public void initAssignmentMarks() {
        VerticalLayout right = new VerticalLayout();
        right.setWidth("230px");

        VerticalLayout marks = new VerticalLayout();

        pending.setVisible(false);
        BootstrapAlertBlock status = new BootstrapAlertBlock("Pending Review");
        editAssignment.setWidth("190px");
        editAssignment.setSize(BootstrapButton.Size.SMALL);
        pending.addComponent(status);
        right.addComponents(editAssignment, pending, marks);
        right.setComponentAlignment(editAssignment, Alignment.TOP_RIGHT);
        marks.setWidth("230px");
        marks.addStyleName("layout-border");

        editAssignment.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                HelloUI.getCurrent().getNavigator().navigateTo(EditAssignment.NAME + "/" + NAME.split("/")[1]);
            }
        });

        /** Track Path **/
        BootstrapHeading trackPathHeading = new BootstrapHeading(1, "Track Path");
        HorizontalLayout trackPath = new HorizontalLayout();
        BootstrapProgressBar progressBar = new BootstrapProgressBar();
        BootstrapParagraph trackPathParagraph = new BootstrapParagraph();

        trackPath.addComponent(progressBar);
        trackPath.addComponent(trackPathParagraph);

        trackPath.setSizeFull();
        progressBar.setSizeFull();
        progressBar.setPercent(33);
        progressBar.setType(BootstrapProgressBar.Style.STRIPED);
        trackPathParagraph.setText("1/3");

        trackPath.setExpandRatio(progressBar, 4);
        trackPath.setExpandRatio(trackPathParagraph, 1);
        trackPath.setComponentAlignment(progressBar, Alignment.MIDDLE_LEFT);
        trackPath.setComponentAlignment(trackPathParagraph, Alignment.MIDDLE_RIGHT);
        trackPathParagraph.setAlignment("MIDDLE_RIGHT");
        trackPathParagraph.setMargin(0);

        /** Badges **/
        Badge badge = new Badge("T", "Temp Badge", "0000FF");
        if (assignment.getBadges() != null) {
            for (String b : assignment.getBadges())
                badge = com.example.hello.views.badges.Badge.GETBadge(b).createBadge();
        }
        BootstrapHeading badgesHeading = new BootstrapHeading(2, "Badges");
        HorizontalLayout badges = new HorizontalLayout();
        BootstrapParagraph badgesParagraph = new BootstrapParagraph();

        badges.addComponents(badge, badgesParagraph);

        badges.setSizeFull();
        badgesParagraph.setText(badge.getName());

        badges.setExpandRatio(badge, 1);
        badges.setExpandRatio(badgesParagraph, 4);
        badges.setComponentAlignment(badge, Alignment.MIDDLE_LEFT);
        badges.setComponentAlignment(badgesParagraph, Alignment.MIDDLE_RIGHT);
        badgesParagraph.setAlignment("MIDDLE_RIGHT");
        badgesParagraph.setMargin(0);

        /** Max Points **/
        BootstrapHeading maxPointsHeading = new BootstrapHeading(3, "Max Points");
        VerticalLayout maxPoints = new VerticalLayout();
        BootstrapParagraph maxPointsSubmissions = new BootstrapParagraph();
        BootstrapParagraph maxPointsReviews = new BootstrapParagraph();

        maxPoints.addComponents(maxPointsSubmissions, maxPointsReviews);

        maxPoints.setSizeFull();
        maxPointsSubmissions.setText(assignment.getSubmissionPoints() + " Submission");
        maxPointsReviews.setText(assignment.getReviewPoints() + " Review");


        // add all of the elements
        marks.addComponents(
                trackPathHeading,
                trackPath,
                badgesHeading,
                badges,
                maxPointsHeading,
                maxPoints
        );

        layout.addComponent(right);
    }

    /**
     * These static methods are intended to be used as an alternative to the HttpRequest class
     * directly. The GET(String get) method can technically return any value type, however this
     * is useful if the user of this methods knows the type of the value that should be returned.
     *
     * These methods currently reside in this View due to this View's name relationship with
     * these methods function. It might be a good idea to move these methods elsewhere later
     * (perhaps in a helper class whose sole purpose is to return the proper POJO).
     */
    public static AssignmentPOJO GET(String get) {
        AssignmentPOJO assignment = new AssignmentPOJO();
        try {
            String json = HttpRequest.GET(get);
            ObjectMapper mapper = new ObjectMapper();
            assignment = mapper.readValue(json, new TypeReference<AssignmentPOJO>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return assignment;
    }

    public static AssignmentPOJO GETAssignment(String assignmentName) {
        AssignmentPOJO assignment = new AssignmentPOJO();
        try {
            String json = HttpRequest.GET(Assignments.NAME + "/" + assignmentName);
            ObjectMapper mapper = new ObjectMapper();
            assignment = mapper.readValue(json, new TypeReference<AssignmentPOJO>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return assignment;
    }

    /**
     * This method is intended to be called after changes have been made to the resource
     * associated with this View. Since the View is persistent due to its initialization
     * (unlike Users, Organizations, etc.), a new View must be created to reflect any changes.
     */
    private static void refreshView(AssignmentPOJO assignment) {
        HelloUI.getCurrent().getNavigator().removeView(Assignments.NAME + "/" + assignment.getEncodedName());
        Assignment newView = new Assignment(assignment.getEncodedName(), assignment);
        HelloUI.getCurrent().getNavigator().addView(newView.NAME, newView);
        HelloUI.getCurrent().getNavigator().navigateTo(newView.NAME);
    }

    /**
     * The methods below are intended to provide the proper JOIN mechanism between
     * related resources.
     */
    public static boolean changeName(AssignmentPOJO assignment, String oldName, String newName) {
        Set<TrackPOJO> tracks = Tracks.GETTracks("?assignment=" + assignment.getEncodedName());
        Set<UserPOJO> users = Users.GETUsers("?assignment=" + assignment.getEncodedName());

        assignment.setName(newName);
        for (TrackPOJO org : tracks) {
            org.removeAssignment(oldName);
            org.addAssignment(newName);
            org.update();
        }
        for (UserPOJO user : users) {
            user.removeAssignment(oldName);
            user.addAssignment(newName);
            user.update();
        }

        return POJO.update(Assignments.NAME + "/" + oldName, assignment);
    }

    public boolean changeTrack(AssignmentPOJO assignment, TrackPOJO fromTrack, TrackPOJO toTrack) {
        assignment.setTrack(toTrack.getEncodedName());
        fromTrack.removeAssignment(assignment.getEncodedName());
        toTrack.addAssignment(assignment.getEncodedName());
        return assignment.update() && fromTrack.update() && toTrack.update();
    }
    
    public boolean addBadge(AssignmentPOJO assignment, BadgePOJO badge, boolean create) {
        assignment.addBadge(badge.getEncodedName());
        return assignment.update() && (!create || badge.create());
    }

    public boolean removeBadge(AssignmentPOJO assignment, BadgePOJO badge) {
        assignment.removeBadge(badge.getEncodedName());
        return assignment.update();
    }

    public boolean addReviewer(AssignmentPOJO assignment, UserPOJO reviewer, boolean create) {
        assignment.addReviewer(reviewer.getEncodedName());
        reviewer.addAssignment(assignment.getEncodedName());
        return assignment.update() && (create ? reviewer.create() : reviewer.update());
    }

    public boolean removeReviewer(AssignmentPOJO assignment, UserPOJO reviewer) {
        assignment.removeReviewer(reviewer.getEncodedName());
        reviewer.removeAssignment(reviewer.getEncodedName());
        return assignment.update() && reviewer.update();
    }

}